Public Class TabStrip
    Inherits PictureBox

    Dim MaxTabWidth As Integer = 180
    Public Tabs As New List(Of Tab)
    Dim TabWidth As Integer = 160

    Event TabSelected()

    Public Function AddTab(ByVal Text As String, ByVal Control As Object, Optional ByVal Locked As Boolean = False) As Tab
        Dim Tab As New Tab With {.Locked = Locked, .Control = Control, .Text = Text, .Strip = Me}
        Tabs.Add(Tab)
        Visible = Tabs.Count > 1
        SelectedTab = Tab
        CalculateTabPositions()
        Application.DoEvents()
        Return Tab
    End Function

    Private Sub TabStrip_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If Cursor <> Cursors.Hand Then Exit Sub
        If SelectedTab.CloseRect.Contains(e.Location) Then SelectedTab.Close() : Exit Sub
        Dim NewTab As Integer = Int(e.X / TabWidth)
        Cursor = Cursors.Default
        SelectedTab = Tabs(NewTab)
        Refresh()
    End Sub

    Private Sub TabStrip_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
        HoverTab = Nothing
        Cursor = Cursors.Default
    End Sub

    Private Sub TabStrip_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Dim Index As Integer = Int(e.X / TabWidth)
        If Index < 0 Then Exit Sub
        HoverTab = If(Index >= Tabs.Count, Nothing, Tabs(Index))
        If Not HoverTab Is Nothing Then HoverClose = HoverTab.CloseRect.Contains(e.Location)
        Cursor = If(HoverTab Is SelectedTab, If(HoverTab.CloseRect.Contains(e.Location), Cursors.Hand, Cursors.Default), If(HoverTab Is Nothing, Cursors.Default, Cursors.Hand))
    End Sub

    Private Sub TabStrip_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        If Width <= 0 Or Height <= 0 Then Exit Sub
        Dim G As Graphics = e.Graphics
        G.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        G.PixelOffsetMode = Drawing2D.PixelOffsetMode.None
        G.FillRectangle(New SolidBrush(SystemColors.Control), -1, -1, Width + 2, Height + 2)
        G.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
        G.DrawLine(New Pen(Color.FromArgb(96, Color.Black)), 0, Height - 2, Width, Height - 2)
        G.DrawLine(New Pen(Color.FromArgb(32, Color.Black)), 0, Height - 3, Width, Height - 3)
        For Each Tab As Tab In Tabs
            Tab.Draw(G, False, False, Height, TabWidth)
        Next
        If Not HoverTab Is Nothing And Not HoverTab Is SelectedTab Then HoverTab.Draw(G, False, True, Height, TabWidth)
        G.DrawLine(Pens.White, 0, Height - 1, Width, Height - 1)
        If Not SelectedTab Is Nothing Then SelectedTab.Draw(G, True, HoverClose, Height, TabWidth)
    End Sub

    Sub CalculateTabPositions()
        If Tabs.Count = 0 Then Exit Sub
        TabWidth = Math.Min((Width - 32) \ Tabs.Count, MaxTabWidth)
        For Each Tab As Tab In Tabs
            Tab.Rect = New Rectangle(Tabs.IndexOf(Tab) * TabWidth - 3, 2, TabWidth + 6, Height)
        Next
        Invalidate()
    End Sub

    Private Sub TabStrip_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        CalculateTabPositions()
    End Sub

    Public Sub Switch(Optional ByVal Direction = 1)
        SelectedTab = Tabs((Tabs.IndexOf(SelectedTab) + Direction + Tabs.Count) Mod Tabs.Count)
    End Sub

    Dim m_SelectedTab As Tab
    Property SelectedTab() As Tab
        Get
            Return m_SelectedTab
        End Get
        Set(ByVal Value As Tab)
            If m_SelectedTab Is Value Then Exit Property
            If Not Value Is Nothing AndAlso Not Value.Control Is Nothing Then
                Value.Control.Dock = DockStyle.Fill
                Value.Control.Visible = True
            End If
            If Not m_SelectedTab Is Nothing AndAlso Not m_SelectedTab.Control Is Nothing Then
                m_SelectedTab.Control.Visible = False
            End If
            m_SelectedTab = Value
        End Set
    End Property


    Dim m_HoverTab As Tab
    Property HoverTab() As Tab
        Get
            Return m_HoverTab
        End Get
        Set(ByVal Value As Tab)
            If m_HoverTab Is Value Then Exit Property
            m_HoverTab = Value
            Invalidate()
        End Set
    End Property

    Dim m_HoverClose As Boolean
    Property HoverClose() As Boolean
        Get
            Return m_HoverClose
        End Get
        Set(ByVal Value As Boolean)
            If m_HoverClose = Value Then Exit Property
            m_HoverClose = Value
            Invalidate()
        End Set
    End Property

    Public Sub CloseTab()
        FindForm.Controls.Remove(SelectedTab.Control)
        Dim Index As Integer = Tabs.IndexOf(SelectedTab)
        Tabs.Remove(SelectedTab)
        CalculateTabPositions()
        If Index = Tabs.Count Then Index -= 1
        SelectedTab = Tabs(Index)
        SelectedTab.Control.Focus()
        Visible = Tabs.Count > 1
    End Sub

End Class


Public Class Tab
    Public Text As String
    Public Rect As Rectangle
    Public Locked As Boolean
    Public Strip As TabStrip

    Dim m_Control As Object
    Dim Image As Image
    Public Property Control() As Object
        Get
            Return m_Control
        End Get
        Set(ByVal Value As Object)
            m_Control = Value
            'If TypeOf Value Is Homepage Then
            '    Image = My.Resources.calendar
            'Else
            '    Image = My.Resources.personel
            'End If
        End Set
    End Property

    Sub Draw(ByVal G As Graphics, ByVal IsSelected As Boolean, ByVal IsHovered As Boolean, ByVal Height As Integer, ByVal TabWidth As Integer)
        If Rect.Width = 0 Then Exit Sub
        Dim F As StringFormat = New StringFormat  'StrFormat("l", "c")
        F.Trimming = StringTrimming.EllipsisCharacter
        F.FormatFlags = F.FormatFlags Or StringFormatFlags.NoWrap
        Dim Path As New Drawing2D.GraphicsPath(Drawing2D.FillMode.Alternate)
        Path.AddLines(New Point() {New Point(Rect.Left, Rect.Bottom), New Point(Rect.Left + Rect.Height \ 4, Rect.Top), New Point(Rect.Right - Rect.Height \ 4, Rect.Top), New Point(Rect.Right, Rect.Bottom)})
        G.DrawPath(New Pen(Color.FromArgb(96, Color.Black), 2), Path)
        Dim Alpha As Integer = If(IsSelected Or IsHovered, 255, 128)
        G.FillPath(New SolidBrush(Color.FromArgb(Alpha, Color.White)), Path)
        Dim ImageRect As New Rectangle(Rect.Left + 4, Rect.Top, Height - 2, Height - 2)
        Dim TextRec As New Rectangle(Rect.Left + ImageRect.Width, 2, Rect.Width - (ImageRect.Width), Height - 2)
        ImageRect.Inflate(-4, -4)
        If Not Image Is Nothing Then G.DrawImage(Image, ImageRect)
        If IsSelected Then TextRec.Width -= Height - 8
        TextRec.Inflate(0, -3)
        If IsSelected Or IsHovered Then
            TextRenderer.DrawText(G, Text, Strip.Font, TextRec, SystemColors.ControlText, Color.Transparent, TextFormatFlags.Left Or TextFormatFlags.VerticalCenter)
        Else
            TextRenderer.DrawText(G, Text, Strip.Font, TextRec, SystemColors.ControlText, Color.Transparent, TextFormatFlags.Left Or TextFormatFlags.VerticalCenter)
        End If
        If IsSelected Then
            Dim R As Rectangle = CloseRect
            If R.Width > 0 Then
                Dim P2 As New Drawing2D.GraphicsPath(Drawing2D.FillMode.Alternate)
                R.Inflate(-2, -2)
                P2.AddLine(R.Left, R.Top, R.Right, R.Bottom)
                P2.StartFigure()
                P2.AddLine(R.Left, R.Bottom, R.Right, R.Top)
                G.DrawPath(New Pen(Color.FromArgb(128, Color.White), 4), P2)
                G.DrawPath(New Pen(Color.FromArgb(IIf(IsHovered, 255, 192), Color.Red), 2), P2)
            End If
        Else
            G.DrawLine(New Pen(Color.FromArgb(128, Color.Black)), Rect.Left, Height - 2, Rect.Right, Height - 2)
            G.DrawLine(New Pen(Color.FromArgb(64, Color.Black)), Rect.Left, Height - 3, Rect.Right, Height - 3)
            G.DrawLine(New Pen(Color.FromArgb(16, Color.Black)), Rect.Left, Height - 4, Rect.Right, Height - 4)
        End If
        'G.DrawPath(New Pen(Color.FromArgb(IIf(IsSelected, 255, 128), Color.White)), Path)
        If Not IsSelected And Not IsHovered Then G.FillPath(New SolidBrush(Color.FromArgb(64, Color.White)), Path)
    End Sub

    ReadOnly Property CloseRect() As Rectangle
        Get
            If Locked Then Return New Rectangle(0, 0, 0, 0)
            Dim R As New Rectangle(Rect.Right - Rect.Height, Rect.Top + 1, Rect.Height, Rect.Height)
            R.Inflate(-7, -7)
            R.Offset(-2, -3)
            Return R
        End Get
    End Property

    Sub Activate()
        Strip.SelectedTab = Me
    End Sub

    Sub SetText(ByVal Text As String)
        Me.Text = Text
        Strip.Invalidate()
    End Sub

    Sub Close()
        Strip.CloseTab()
    End Sub

End Class